iT邦幫忙

2022 iThome 鐵人賽

DAY 30
0
Web 3

如何打造屬於自己的區塊鏈錢包服務系列 第 31

[Day 30] Elrond full node (十九)

  • 分享至 

  • xImage
  •  

今天就是最後一天啦!今年雖然也是充滿波折,但還是順利完賽

今天來完成剩下的API,首先是登入的API,這邊只實作帶Address和pem檔案做驗證登入,按實際作法是登入後會在server中儲存資料和發給認證(例如JWT token)然後用認證來做後續實作。
首先是要新增一個saved的資料夾存放上傳的檔案,這邊要特別建議如果要真的拿來實際應用的話,需要轉出成json檔案,因為json檔案可以設定密碼,這樣會比較安全。
https://ithelp.ithome.com.tw/upload/images/20221014/20140358Q86KqDsW6I.png
再來是GetBalance和withdraw,這邊都需要做認證,但我們今天沒有做JWT認證,只單純實作API。
api/routes/api.go

package routes

import "elrondWallet/api/controllers"

func init() {

	// unauthorized
	unauthorizedAPI := engine.Group("api/v1/wallet")
	{
		unauthorizedAPI.GET("/mnemonic", controllers.Mnemonic)
		unauthorizedAPI.POST("/pem", controllers.DownloadPem)
		unauthorizedAPI.POST("/:address/login", controllers.Login)
		unauthorizedAPI.GET("/:address/balance", controllers.GatBalance)
		unauthorizedAPI.POST("/:address/withdraw", controllers.Withdraw)
	}
}

api/controllers/wallet.go

package controllers

import (
	walletUtils "elrondWallet/internal/wallet"
	"fmt"
	"github.com/gin-gonic/gin"
	"math"
	"net/http"
	"path/filepath"
)

func Mnemonic(c *gin.Context) {
	mnemonic, _ := walletUtils.GenerateNewMnemonic()
	c.JSON(200, gin.H{
		"code":     "00",
		"mnemonic": mnemonic,
	})
}

type MnemonicReq struct {
	Mnemonic string `json:"mnemonic"`
}

type WithdrawReq struct {
	Receiver string  `json:"receiver"`
	Sender   string  `json:"sender"`
	Amount   float64 `json:"amount"`
}

func DownloadPem(c *gin.Context) {
	var ap MnemonicReq
	if err := c.ShouldBindJSON(&ap); err != nil {
		c.JSON(400, gin.H{"error": "Calculator error"})
		return
	}
	privateKey := walletUtils.GetPrivateKeyFromMnemonic(ap.Mnemonic, 0, 0)
	address, _ := walletUtils.GetAddressFromPrivateKey(privateKey)
	err := walletUtils.SavePrivateKeyToPemFile(privateKey, address)
	if err != nil {
		return
	}
	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Content-Disposition", "attachment; filename="+address+".pem")
	c.Header("Content-Type", "application/octet-stream")
	c.File(address + ".pem")

}

func Login(c *gin.Context) {
	file, _ := c.FormFile("file")
	filename := filepath.Base(file.Filename)
	fmt.Println("filename", filename)
	filePath := "saved/" + filename
	if err := c.SaveUploadedFile(file, filePath); err != nil {
		// 存檔失敗時的錯誤處理
		c.String(http.StatusBadRequest, fmt.Sprintf("upload file err: %s", err.Error()))
		return
	}

	privateKey, _ := walletUtils.LoadPrivateKeyFromPemFile(filePath)
	address, _ := walletUtils.GetAddressFromPrivateKey(privateKey)
	if address != c.Param("address") {
		c.String(http.StatusBadRequest, fmt.Sprintf("File %s address and param address not match.", file.Filename))
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    "00",
		"message": "login success!",
	})
}

func GatBalance(c *gin.Context) {
	address, _ := getAddressFromReq(c)
	balance := walletUtils.GetAddressBalance(address)
	c.JSON(http.StatusOK, gin.H{
		"code":    "00",
		"balance": balance,
	})
}

func Withdraw(c *gin.Context) {
	address, privateKey := getAddressFromReq(c)
	var withdrawReq WithdrawReq
	if err := c.ShouldBindJSON(&withdrawReq); err != nil {
		c.JSON(400, gin.H{"error": "Calculator error"})
		return
	}
	if address != c.Param("address") {
		c.String(http.StatusBadRequest, fmt.Sprintf("Json address and param address not match."))
		return
	}
	addressNonce := walletUtils.GetAddressNonce(address)

	code := walletUtils.SentTransaction(withdrawReq.Sender, withdrawReq.Receiver, fmt.Sprint(
		int(withdrawReq.Amount*(math.Pow(10, 18)))), addressNonce, 1000000000, 50000, privateKey)
	c.JSON(http.StatusOK, gin.H{
		"code":    "00",
		"message": code,
	})
}

func getAddressFromReq(c *gin.Context) (string, []byte) {
	address := c.Param("address")
	filePath := "saved/" + address + ".pem"
	privateKey, _ := walletUtils.LoadPrivateKeyFromPemFile(filePath)
	address, _ = walletUtils.GetAddressFromPrivateKey(privateKey)
	return address, privateKey
}

測試結果
Login
https://ithelp.ithome.com.tw/upload/images/20221014/20140358Jz0F69hIUx.png
Balanace
https://ithelp.ithome.com.tw/upload/images/20221014/20140358drzhYOsXlA.png
Sent transaction
https://ithelp.ithome.com.tw/upload/images/20221014/201403587hrm4Sy0k7.png
https://ithelp.ithome.com.tw/upload/images/20221014/201403587K04m3kFDq.png
鏈上紀錄
以上就是這次鐵人挑戰賽的全部啦,希望各位有從我雜亂的文章中學到點什麼,這次練習的Repo,這次完賽的心得是真的要事先打好稿而且示範的專案最好是事先準備好,有時一卡Bug就真的會難產,希望明年的鐵人賽可以更加的有架構性的去分享給大家。


上一篇
[Day 29] Elrond full node (十八)
系列文
如何打造屬於自己的區塊鏈錢包服務31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言